package com.aco.fatureapp.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import android.annotation.SuppressLint;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import com.aco.fatureapp.activity.SearchMeteringActivity.TypeFilter;
import com.aco.fatureapp.model.Dashboard;
import com.aco.fatureapp.model.Fotografia;
import com.aco.fatureapp.model.Help;
import com.aco.fatureapp.model.Imovel;
import com.aco.fatureapp.model.Impressora;
import com.aco.fatureapp.model.Ocorrencia;
import com.aco.fatureapp.model.Roteiro;
import com.aco.fatureapp.model.billing.Conta;
import com.aco.fatureapp.model.billing.LancamentoCobrado;
import com.aco.fatureapp.model.billing.LogCorrecaoConta;
import com.aco.fatureapp.model.billing.LogLeitura;
import com.aco.fatureapp.model.billing.Produto;
import com.aco.fatureapp.model.billing.Valor;
import com.aco.fatureapp.model.billing.Volume;
import com.aco.fatureapp.model.printer.PrinterResumo;
import com.aco.fatureapp.utilitary.DataUtils;
import com.google.inject.Inject;
import com.orm.SugarApp;
import com.orm.SugarDb;
import com.orm.SugarRecord;
import com.orm.query.Select;

@SuppressLint("UseSparseArrays")
public class SrvMetering {

	private SQLiteDatabase database = null;
	private Long retorno;

	private static final int DIAS_PERMITIR_FATURAR = 3;

	@Inject
	public SrvMetering() {
		super();

		database = new SugarDb(SugarApp.getSugarContext())
				.getWritableDatabase();
	}

	public int buscarOrdemUltimaLeitura() {
		final Cursor cursor = database.rawQuery(
				"SELECT MAX(ordem_roteiro) FROM imovel", null);

		cursor.moveToFirst();

		if (cursor.getCount() > 0) {

			retorno = cursor.getLong(0);

			cursor.close();

			return retorno.intValue();
		}

		cursor.close();

		return 0;
	}

	public Imovel getPrimeiraLeitura() {
		final List<Imovel> lstImovel = Select.from(Imovel.class)
				.orderBy("ORDEM_ROTEIRO ASC").limit("1").list();

		if (lstImovel != null && !lstImovel.isEmpty()) {
			return lstImovel.iterator().next();
		}

		return null;
	}

	public Imovel proximaLeitura(final Integer ordemAtual) {

		final String[] param = { ordemAtual.toString() };

		final List<Imovel> lstImovel = Select.from(Imovel.class)
				.where("ORDEM_ROTEIRO > ?", param).orderBy("ORDEM_ROTEIRO ASC")
				.limit("1").list();

		if (lstImovel != null && !lstImovel.isEmpty()) {
			return lstImovel.iterator().next();
		}

		return null;
	}

	public Imovel leituraAnterior(final Integer ordemAtual) {

		final String[] param = { ordemAtual.toString() };

		final List<Imovel> lstImovel = Select.from(Imovel.class)
				.where("ORDEM_ROTEIRO < ?", param)
				.orderBy("ORDEM_ROTEIRO DESC").limit("1").list();

		if (lstImovel != null && !lstImovel.isEmpty()) {
			return lstImovel.iterator().next();
		}

		return null;
	}

	public String getDescricaoOcorrencia(final Long codOcorrencia) {

		final String[] param = { codOcorrencia.toString() };

		final List<Ocorrencia> lstOcorrencia = Select.from(Ocorrencia.class)
				.where("CODIGO = ?", param).list();

		if (lstOcorrencia != null && !lstOcorrencia.isEmpty()) {
			return lstOcorrencia.iterator().next().getDescricao();
		}

		return null;
	}

	/**
	 * Método responsável por fechar a conexão com a base de dados.
	 */
	public void closeDB() {
		database.close();
	}

	public Imovel findLeitura(TypeFilter typeFilter, String param) {

		String condition = "INSCRICAO=?";

		String[] params = { param.toString() };

		switch (typeFilter) {
		case FILTRO_HIDROMETRO: {
			condition = "NUMERO_HIDROMETRO LIKE ?";
			String[] params2 = { "%" + param + "%" };
			params = params2;
			break;
		}
		case FILTRO_INSCRICAO: {
			condition = "INSCRICAO=?";
			break;
		}
		case FILTRO_POSICAO: {
			condition = "ORDEM_ROTEIRO=?";
			break;
		}
		}

		final List<Imovel> lstImovel = Select.from(Imovel.class)
				.where(condition, params).limit("1").list();

		if (lstImovel != null && !lstImovel.isEmpty()) {
			return lstImovel.iterator().next();
		}

		return null;
	}

	public List<Help> getLstOcorrencia(String filterParameter) {
		Select<Ocorrencia> select = Select.from(Ocorrencia.class);

		if (filterParameter != null) {
			String[] param = { "%" + filterParameter + "%" };
			select.where("DESCRICAO LIKE ?", param);
		}

		select.orderBy("CODIGO");

		List<Ocorrencia> lstOcorrencia = select.list();

		if (lstOcorrencia != null && !lstOcorrencia.isEmpty()) {

			List<Help> lstReturn = new ArrayList<Help>();

			for (Ocorrencia ocorrencia : lstOcorrencia) {
				Help help = new Help();
				help.id = ocorrencia.getIdIntegracao();
				help.codigo = ocorrencia.getCodigo();
				help.descricao = ocorrencia.getDescricao();

				lstReturn.add(help);
			}

			return lstReturn;
		}

		return null;
	}

	public Help getOcorrencia(Long mCodOcorrencia) {
		String whereArgs = mCodOcorrencia.toString();

		ListIterator<Ocorrencia> listIterator = SugarRecord.find(
				Ocorrencia.class, "CODIGO = ?", whereArgs).listIterator();

		if (listIterator != null && listIterator.hasNext()) {
			Ocorrencia ocorrencia = listIterator.next();

			Help ocorrenciaVo = new Help();
			ocorrenciaVo.id = ocorrencia.getIdIntegracao();
			ocorrenciaVo.codigo = ocorrencia.getCodigo();
			ocorrenciaVo.descricao = ocorrencia.getDescricao();

			return ocorrenciaVo;
		}
		return null;
	}

	/**
	 * Apagar os dados faturados do roteiro inteiro.
	 */
	public void deleteAllBilling() {
		SugarRecord.deleteAll(LancamentoCobrado.class);
		SugarRecord.deleteAll(LogCorrecaoConta.class);
		SugarRecord.deleteAll(Produto.class);
		SugarRecord.deleteAll(Valor.class);
		SugarRecord.deleteAll(Volume.class);
		SugarRecord.deleteAll(Fotografia.class);
		SugarRecord.deleteAll(LogLeitura.class);
		SugarRecord.deleteAll(Conta.class);
	}

	public Imovel previousNotCompleted(Integer ordemAtual) {

		final String[] param = { ordemAtual.toString() };

		final Cursor cursor = database.rawQuery(
				"SELECT IMO.ID FROM IMOVEL IMO WHERE IMO.ORDEM_ROTEIRO < ? "
						+ " AND NOT EXISTS (SELECT 1 FROM LOG_LEITURA LOG "
						+ " WHERE IMO.INSCRICAO=LOG.INSCRICAO) "
						+ " ORDER BY ORDEM_ROTEIRO DESC", param);

		cursor.moveToFirst();

		if (cursor.getCount() > 0) {

			final Long retorno = cursor.getLong(0);

			if (retorno != null) {
				Imovel imovel = SugarRecord.findById(Imovel.class, retorno);

				cursor.close();

				return imovel;
			}
		}

		cursor.close();

		return null;
	}

	public Imovel nextNotCompleted(Integer ordemAtual) {
		try {
			SugarRecord
					.executeQuery("CREATE INDEX IX_IMOVEL_ORDEM ON IMOVEL(INSCRICAO, ORDEM_ROTEIRO)");

			SugarRecord
					.executeQuery("CREATE INDEX IX_ORDEM ON IMOVEL(ORDEM_ROTEIRO)");

			SugarRecord
					.executeQuery("CREATE INDEX IX_LOG_INSCRICAO ON LOG_LEITURA(INSCRICAO)");
		}
		catch (Exception ex) {
			Log.d("Criar do índice de imovel", ex.getMessage());
		}

		final String[] param = { ordemAtual.toString() };

		final Cursor cursor = database.rawQuery(
				"SELECT IMO.ID FROM IMOVEL IMO WHERE IMO.ORDEM_ROTEIRO > ? "
						+ " AND NOT EXISTS (SELECT 1 FROM LOG_LEITURA LOG "
						+ " WHERE IMO.INSCRICAO=LOG.INSCRICAO) "
						+ " ORDER BY ORDEM_ROTEIRO ASC", param);

		cursor.moveToFirst();

		if (cursor.getCount() > 0) {

			final Long retorno = cursor.getLong(0);

			if (retorno != null) {
				Imovel imovel = SugarRecord.findById(Imovel.class, retorno);
				cursor.close();

				return imovel;
			}
		}

		cursor.close();
		return null;
	}

	public Dashboard getResumo() {

		final Cursor cursor = database
				.rawQuery(
						"SELECT DATA_LEITURA, "
								+ " (SELECT COUNT(*) FROM LOG_LEITURA WHERE COD_OCORRENCIA1 > 0 ) AS COM_OCORRENCIA, "
								+ " (SELECT COUNT(*) FROM LOG_LEITURA ) AS TOTAL, "
								+ " (SELECT COUNT(*) FROM IMOVEL IMO WHERE NOT EXISTS (SELECT 1 FROM LOG_LEITURA LOG WHERE IMO.INSCRICAO=LOG.INSCRICAO ) ) AS PENDENTES, "
								+ " (SELECT COUNT(*) FROM LOG_LEITURA WHERE CONTA_RETIDA >= 0 ) AS COM_OCORRENCIA "
								+ " FROM LOG_LEITURA ORDER BY DATA_LEITURA LIMIT 1",
						null);

		cursor.moveToFirst();

		if (cursor.getCount() > 0) {

			Dashboard dashboard = new Dashboard();
			dashboard.dataPrimeiraLeitura = cursor.getLong(0);
			dashboard.qtdComOcorrencia = cursor.getLong(1);
			dashboard.qtdConcluidas = cursor.getLong(2);
			dashboard.qtdPendentes = cursor.getLong(3);
			dashboard.qtdRetidas = cursor.getLong(4);

			cursor.close();

			return dashboard;
		}

		cursor.close();
		return null;
	}

	public String getMacImpressora() {

		Iterator<Impressora> iterator = Impressora.find(Impressora.class,
				"FLG_PADRAO = ?", new String[] { "1" }).iterator();

		if (iterator != null && iterator.hasNext()) {
			String macPrinter = iterator.next().getEnderecoMac();

			return macPrinter;
		}

		return null;
	}

	public boolean isImpressoraAtiva() {

		Iterator<Impressora> iterator = Impressora.find(Impressora.class,
				"FLG_PADRAO = ?", new String[] { "1" }).iterator();

		if (iterator != null && iterator.hasNext()) {
			boolean macPrinter = iterator.next().getFlgDisponivel();

			return macPrinter;
		}

		return false;
	}

	public List<PrinterResumo> getLstPrinterResumo() {

		final Cursor cursor = database
				.rawQuery(
						"SELECT LOG.ID, IMO.ORDEM_ROTEIRO, IMO.INSCRICAO, LOG.LEITURA, LOG.DATA_LEITURA,"
								+ " LOG.COD_OCORRENCIA1, LOG.ID_LEITURISTA, LOG.CONTA_RETIDA, LOG.CONTA_REGERADA "
								+ " FROM IMOVEL IMO, LOG_LEITURA LOG "
								+ " WHERE LOG.INSCRICAO = IMO.INSCRICAO AND LOG.PRINT_RESUMO = 0",
						null);

		return montarResumo(cursor);
	}

	public List<PrinterResumo> getLstPrinterResumoTodas() {

		final Cursor cursor = database
				.rawQuery(
						"SELECT LOG.ID, IMO.ORDEM_ROTEIRO, IMO.INSCRICAO, LOG.LEITURA, LOG.DATA_LEITURA,"
								+ " LOG.COD_OCORRENCIA1, LOG.ID_LEITURISTA, LOG.CONTA_RETIDA, LOG.CONTA_REGERADA "
								+ " FROM IMOVEL IMO LEFT JOIN LOG_LEITURA LOG ON ( LOG.INSCRICAO = IMO.INSCRICAO ) "
								+ " ORDER BY ORDEM_ROTEIRO", null);

		return montarResumo(cursor);
	}

	public List<PrinterResumo> getLstPrinterResumoParcial(
			Integer posicaoInicial, Integer posicaoFinal) {

		String[] param = new String[] { posicaoInicial.toString(),
				posicaoFinal.toString() };

		final Cursor cursor = database
				.rawQuery(
						"SELECT LOG.ID, IMO.ORDEM_ROTEIRO, IMO.INSCRICAO, LOG.LEITURA, LOG.DATA_LEITURA,"
								+ " LOG.COD_OCORRENCIA1, LOG.ID_LEITURISTA, LOG.CONTA_RETIDA, LOG.CONTA_REGERADA "
								+ " FROM IMOVEL IMO LEFT JOIN LOG_LEITURA LOG ON ( LOG.INSCRICAO = IMO.INSCRICAO )"
								+ " WHERE IMO.ORDEM_ROTEIRO BETWEEN ?  AND ? "
								+ " ORDER BY ORDEM_ROTEIRO", param);

		return montarResumo(cursor);
	}

	private List<PrinterResumo> montarResumo(final Cursor cursor) {
		cursor.moveToFirst();

		if (cursor.getCount() > 0) {

			List<PrinterResumo> lstPrinterResumo = new ArrayList<PrinterResumo>();

			do {

				PrinterResumo printerResumo = new PrinterResumo();
				printerResumo.setId(cursor.getLong(0));
				printerResumo.setPosicao(cursor.getLong(1));
				printerResumo.setInscricao(cursor.getLong(2));
				printerResumo.setLeitura(cursor.getLong(3));

				Long hora = cursor.getLong(4);
				String dataFormatada = "00:00";
				if (hora != null && hora > 0L) {
					dataFormatada = DataUtils.dataFormatada(hora, "hh:mm");
				}

				printerResumo.setHora(dataFormatada);

				printerResumo.setOcorrencia(cursor.getLong(5));
				printerResumo.setMatricula(cursor.getLong(6));
				printerResumo.setTipoEntrega(0);
				printerResumo.setRetida(cursor.getInt(7));
				printerResumo.setRefaturada(cursor.getInt(8));

				lstPrinterResumo.add(printerResumo);
			}
			while (cursor.moveToNext());

			cursor.close();

			return lstPrinterResumo;
		}

		cursor.close();
		return null;
	}

	public Roteiro getRoteiro() {
		Iterator<Roteiro> lstRoteiro = Roteiro.findAll(Roteiro.class);

		if (lstRoteiro != null && lstRoteiro.hasNext()) {

			return lstRoteiro.next();
		}

		return null;
	}

	public boolean isImprimirResumo() {

		boolean isTemResumoNaFila = false;

		// boolean isTemResumoNaFila = existeResumoNaFilaImpressao();

		if (isImprimirResumo(isTemResumoNaFila) || isTodasLeiturasEfetuadas()) {
			return true;
		}

		return false;
	}

	public boolean isImprimirResumo(final boolean isTemResumoNaFila) {

		final Cursor cursor = database.rawQuery("SELECT QTDE_EMITIR_RESUMO, "
				+ " ( SELECT  COUNT(*) FROM LOG_LEITURA "
				+ " WHERE PRINT_RESUMO = 0  ) FROM CONFIGURACAO_APP", null);

		cursor.moveToFirst();

		if (cursor.getCount() > 0) {
			final int qtdParam = cursor.getInt(0);

			final int qtdEmitirResumo = cursor.getInt(1);

			if (qtdEmitirResumo > 0) {
				if (qtdEmitirResumo == qtdParam) {
					return true;
				}

				/* Caso aconteça algum erro e não emitiu na conta 50. */
				if (isTemResumoNaFila && qtdEmitirResumo > qtdParam) {
					int qtdNovoResumo = qtdEmitirResumo - qtdParam;

					if (qtdNovoResumo == qtdParam) {
						return true;
					}

					if (qtdNovoResumo > qtdParam) {
						return true;
					}
				}
				else if (!isTemResumoNaFila && qtdEmitirResumo > qtdParam) {
					return true;
				}
			}

			return false;
		}

		return false;
	}

	public boolean isTodasLeiturasEfetuadas() {

		final Cursor cursor = database.rawQuery(
				"SELECT COUNT(*), ( SELECT COUNT(*) FROM LOG_LEITURA ) AS TOTAL "
						+ " FROM IMOVEL", null);

		cursor.moveToFirst();

		if (cursor.getCount() > 0) {
			final Long lidos = cursor.getLong(0);

			final Long total = cursor.getLong(1);

			return lidos.equals(total);
		}

		return false;
	}

	public void markBillPrinting(List<PrinterResumo> lstPrinterResumo) {
		if (lstPrinterResumo != null && !lstPrinterResumo.isEmpty()) {

			for (PrinterResumo printerResumo : lstPrinterResumo) {

				LogLeitura logLeitura = LogLeitura.findById(LogLeitura.class,
						printerResumo.getId());
				logLeitura.setPrintResumo(true);
				logLeitura.save();
			}
		}
	}

	public Long getIdCarga() {

		final Cursor cursor = database.rawQuery(
				"SELECT ID_CARGA FROM IMOVEL IMO LIMIT 1", null);

		cursor.moveToFirst();

		if (cursor.getCount() > 0) {

			Long retorno = cursor.getLong(0);

			cursor.close();

			return retorno;
		}

		cursor.close();

		return null;
	}

	public boolean validarPrazoLeitura(Long dataFaturamentoE) {

		if (dataFaturamentoE != null) {
			Calendar dataFaturamento = Calendar.getInstance();
			dataFaturamento.setTimeInMillis(dataFaturamentoE);

			Calendar dataMaximaFaturamento = Calendar.getInstance();
			dataMaximaFaturamento.setTimeInMillis(dataFaturamentoE);
			dataMaximaFaturamento.add(Calendar.DAY_OF_YEAR,
					DIAS_PERMITIR_FATURAR);

			Calendar dataAtual = Calendar.getInstance();

			if (dataAtual.before(dataFaturamento)) {
				return true;
			}

			if (dataAtual.after(dataMaximaFaturamento)) {
				return true;
			}
		}

		return false;
	}

	public Integer marcarQtdImpressao(Long inscricao) {

		LogLeitura logLeitura = getLogLeitura(inscricao.toString());

		if (logLeitura != null) {
			Integer qtdImpressao = 1;

			if (logLeitura.getQtdeImpressao() != null
					&& logLeitura.getQtdeImpressao().intValue() >= 1) {
				qtdImpressao = logLeitura.getQtdeImpressao().intValue();
				qtdImpressao++;
			}

			logLeitura.setQtdeImpressao(qtdImpressao.longValue());
			logLeitura.save();

			return qtdImpressao;
		}

		return 1;
	}

	public LogLeitura getLogLeitura(String inscricao) {
		final String[] param = { inscricao };

		LogLeitura logLeitura = Select.from(LogLeitura.class)
				.where("INSCRICAO = ?", param).first();

		return logLeitura;
	}
}
